//
// Created by user on 20-4-16.
//

#include "SMP.h"
#include "Schedule.h"

spinlock_T SMPLock;

void SMPInit() {

    int i;
    unsigned int a, b, c, d;

    //get local APIC ID
    for (i = 0;; i++) {

        getCpuId(0xb, i, &a, &b, &c, &d);

        if ((c >> 8 & 0xff) == 0)
            break;

        printfColor(WHITE, BLACK,
                    "local APIC ID Package_../Core_2/SMT_1,type(%lx) Width: %lx,num of logical processor(%lx)\n",
                    c >> 8 & 0xff, a & 0x1f, b & 0xff);

    }

    printfColor(WHITE, BLACK, "x2APIC ID level: %lx\tx2APIC ID the current logical processor: %lx\n", c & 0xff, d);

    memcpy((unsigned char *) 0xffff800000020000, APUBootStart,
           (unsigned long) &APUBootEnd - (unsigned long) &APUBootStart);

    // 初始化自旋锁
    spinInit(&SMPLock);

    // 设置IPI中断门
    for (i = 200; i < 210; i++) {
        set_intr_gate(i, 2, SMPInterrupt[i - 200]);
    }

    // 清空SMPIPIDesc数组
    memset(SMPIPIDesc, 0, sizeof(IRPDescriptorTable) * 10);

    // 注册IPI 0x200中断处理函数
    registerIPI(200, &IPI_0x200, NULL, NULL, "IPI 0x200");

}


void StartSMP() {

    unsigned int x, y;

    printfColor(RED, YELLOW, "APU starting......\n");

    // 1. 开启 xAPIC 和 x2APIC
    __asm__ __volatile__(    "movq 	$0x1b,	%%rcx	\n\t"
            "rdmsr	\n\t"
            "bts	$10,	%%rax	\n\t"
            "bts	$11,	%%rax	\n\t"
            "wrmsr	\n\t"
            "movq 	$0x1b,	%%rcx	\n\t"
            "rdmsr	\n\t"
    :"=a"(x), "=d"(y)
    :
    :"memory");

    // 2. 判断开启 xAPIC 和 x2APIC 是否成功
    if (x & 0xc00)
        printfColor(RED, YELLOW, "xAPIC & x2APIC enabled\n");

    // 3. 开启 Local APIC 和 EOI 广播
    __asm__ __volatile__(    "movq 	$0x80f,	%%rcx	\n\t"
            "rdmsr	\n\t"
            "bts	$8,	%%rax	\n\t"
//				"bts	$12,	%%rax\n\t"
            "wrmsr	\n\t"
            "movq 	$0x80f,	%%rcx	\n\t"
            "rdmsr	\n\t"
    :"=a"(x), "=d"(y)
    :
    :"memory");

    // 4. 判断开启Local APIC是否成功
    if (x & 0x100)
        printfColor(RED, YELLOW, "SVR[8] enabled\n");

    // 5. 判断禁止广播EOI消息是否成功
    if (x & 0x1000)
        printfColor(RED, YELLOW, "SVR[12] enabled\n");

    // 6. 获取Local APIC的ID值
    __asm__ __volatile__(    "movq $0x802,	%%rcx	\n\t"
            "rdmsr	\n\t"
    :"=a"(x), "=d"(y)
    :
    :"memory");

    printfColor(RED, YELLOW, "x2APIC ID: %lx\n", x);

    current->state = TASK_RUNNING;
    current->flags = PF_KTHREAD;
    current->memorySpaceDistribution = &memorySpaceDistribution;

    listInit(&current->list);
    current->addressLimit = 0xffff800000000000;
    current->priority = 2;
    current->vrunTime = 0;


    current->thread = (Thread *) (current + 1);
    memset(current->thread, 0, sizeof(Thread));
    current->thread->rsp0 = _stack_start;
    current->thread->rsp = _stack_start;
    current->thread->fs = KERNEL_DS;
    current->thread->gs = KERNEL_DS;
    initTask[SMPCPUID()] = current;

    // 加载TSS段描述符
    loadTR(10 + (globalAPUNumber - 1) * 2);

    // 解开自旋锁
    spinUnlock(&SMPLock);

    current->preemptCount = 0;

//    x = 1/0;

    sti();

    // 7. 指示处理器进入中止状态
    while (1)
            hlt();
}


void IPI_0x200(unsigned long nr, unsigned long parameter, PerformSite *regs) {

    switch (current->priority) {
        case 0:
        case 1:
            taskSchedule[SMPCPUID()].CPUExecTaskJiffies--;
            current->vrunTime += 1;
            break;
        case 2:
        default:
            taskSchedule[SMPCPUID()].CPUExecTaskJiffies -= 2;
            current->vrunTime += 2;
            break;
    }

    if (taskSchedule[SMPCPUID()].CPUExecTaskJiffies <= 0)
        current->flags |= NEED_SCHEDULE;

}